/**
 * MIT License
 *
 * Copyright (c) 2024 小村程序员
 * Email: 397237738@qq.com
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.open.cobertura.core.analyzer;

import org.objectweb.asm.Label;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.open.cobertura.core.model.InstructionStateful;
import org.open.cobertura.core.model.JumpInstruction;
import org.open.cobertura.core.util.CoberturaLabelStatefulUtil;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


public class CoberturaInstructionFactory {

    /**
     * 当前的探针数据
     */
    private final boolean[] probes;

    /**
     * 印射指令对应的行
     */

    private int currentLine;
    private InstructionStateful currentInstruction;
    private final Map<AbstractInsnNode,InstructionStateful> instructionStatefulMap;

    /**
     * 印射指令对应的标签
     */
    private final List<Label> currentLable;
    private List<JumpInstruction> jumpList;

    public CoberturaInstructionFactory(boolean[] probes) {
        this.probes = probes;
        this.currentLine=0;
        this.currentInstruction=null;
        this.instructionStatefulMap=new LinkedHashMap<>();
        this.currentLable=new ArrayList<>(2);
        this.jumpList=new ArrayList<>();
    }

    /**
     * 添加指令
     * @param node
     */
    public void addInstruction(final AbstractInsnNode node){
        //排除访问探针方法的指令 2024-11-21 fixed
        if(node==null){
            return;
        }
        final InstructionStateful instructionStateful=new InstructionStateful(currentLine);
        final int labelSize=currentLable.size();
        if(labelSize>0){
            for(int j=labelSize-1;j>=0;j--){
                CoberturaLabelStatefulUtil.setInstruction(currentLable.get(j),instructionStateful);
            }
            currentLable.clear();
        }
        //默认就是一个分支，如果遇到了就+1，一般一个判定条件算2个分支
        if(currentInstruction!=null){
            currentInstruction.setBranch(instructionStateful,0);
        }
        currentInstruction=instructionStateful;
        instructionStatefulMap.put(node,instructionStateful);
    }

    /**
     * 添加跳转指令
     * @param label
     * @param branch
     */
    public void addJumpInstruction(final Label label,final int branch){
        jumpList.add(new JumpInstruction(currentInstruction,label,branch));
    }

    /**
     * 添加探针
     * @param index 探针的索引
     */
    public void addProbe(final int index,final int branch){
        boolean executed=false;
        if(probes!=null){
            executed=probes[index];
        }
        currentInstruction.setBranch(executed,branch);
    }

    /**
     * 添加Label标签
     * @param label
     */
    public void addLabel(final Label label){
        currentLable.add(label);
        //如果不是潜在的指令需要将指令清空，这个Label标签不能被计算覆盖率
        if(!CoberturaLabelStatefulUtil.isNext(label)){
            this.currentInstruction=null;
        }
    }

    /**
     * 清空当前指令
     */
    public void clearCurrentInstruction(){
        this.currentInstruction=null;
    }

    public void addCurrentLine(final int lineNumber){
        this.currentLine=lineNumber;
    }

    /**
     * 得到有状态的指令
     * @return
     */
    public Map<AbstractInsnNode,InstructionStateful> getInstructionStatefulMap(){
        for(JumpInstruction jumpInstruction:jumpList){
            jumpInstruction.setBranch();
        }
        return instructionStatefulMap;
    }


}
